package studyguide.ch18;

import java.io.IOException;
import java.io.InputStream;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.StringItem;
import javax.microedition.media.Control;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.FramePositioningControl;
import javax.microedition.media.control.GUIControl;
import javax.microedition.media.control.MIDIControl;
import javax.microedition.media.control.MetaDataControl;
import javax.microedition.media.control.PitchControl;
import javax.microedition.media.control.RateControl;
import javax.microedition.media.control.RecordControl;
import javax.microedition.media.control.StopTimeControl;
import javax.microedition.media.control.TempoControl;
import javax.microedition.media.control.ToneControl;
import javax.microedition.media.control.VideoControl;
import javax.microedition.media.control.VolumeControl;

public class MediaPlayingForm extends Form {

	private static final String NOT_PLAYING = "not playing";
	private static final String PLAYING = "playing";
	
	private final SoundPlayerMidlet parent;
	private final Command backCommand;
	private final Gauge volumeField;
	private final Gauge repeat;
	private final StringItem play;
	private final StringItem status;
	private final StringItem details;
	
	private Player player;
	
	private class PlayerCommandListener implements CommandListener {
		public void commandAction(Command command, Displayable d) {
			if (command == backCommand) {
				player.close();
				parent.showMainScreen();
			} else {
				throw new RuntimeException("UNKNOWN COMMAND:" + command);
			}
		}
	}
	
	private class PlayerStateListener implements PlayerListener {

		public void playerUpdate(Player player, String event, Object eventData) {
			try {
				System.out.println("Event [" + event + "] at player with data [" + eventData + "]");
				if (STARTED.equals(event)) {
					status.setText(MediaPlayingForm.PLAYING);
				} else if (END_OF_MEDIA.equals(event) 
						   || STOPPED.equals(event)) {
					status.setText(MediaPlayingForm.NOT_PLAYING);
					// When fast-forward was used, we need to reset the media time again
					if (player.getState() != Player.CLOSED) {
						player.setMediaTime(0);
					}
				}
			} catch (MediaException e) {
				throw new RuntimeException("Error:" + e);
			}
		}
		
	}
	
	public MediaPlayingForm(SoundPlayerMidlet parent) {
		super("Tone");
		this.parent = parent;
		volumeField = new Gauge("Volume:", true, 10, 9);
		repeat = new Gauge("Repeat:", true, 3, 0);
		play = new StringItem("Play", null, StringItem.BUTTON);
		status = new StringItem("Status:", NOT_PLAYING, StringItem.BUTTON);
		details = new StringItem("Details:", "", StringItem.PLAIN);
		
		append(play);
		append(volumeField);
		append(repeat);
		append(status);
		append(details);
		
		backCommand = new Command("Back", Command.BACK, 1);
		
		addCommand(backCommand);
		setCommandListener(new PlayerCommandListener());
		
		play.setDefaultCommand(new Command("Play", Command.SCREEN, 1));
		play.setItemCommandListener(new ItemCommandListener() {
			public void commandAction(Command c, Item item) {
				// Play
				try {
					if (player.getState() == Player.PREFETCHED) {
						player.setLoopCount(repeat.getValue() + 1);
						player.start();
					}
				} catch (MediaException e) {
					throw new RuntimeException("Error:" + e);
				}
			}
		});
		
		status.setDefaultCommand(new Command("Fast-forward", Command.ITEM, 1));
		status.setItemCommandListener(new ItemCommandListener() {
			public void commandAction(Command c, Item item) {
				// Fast forward:
				if (player.getState() == Player.STARTED) {
					try {
						player.setMediaTime(
								player.getMediaTime()
								 + 1 * (1000*1000));
					} catch (MediaException e) {
						throw new RuntimeException("Error:" + e);
					}
				}
			}
		});
		
		this.setItemStateListener(new ItemStateListener() {
			public void itemStateChanged(Item item) {
				if (item == volumeField) {
					VolumeControl volume = (VolumeControl) player.getControl("VolumeControl");
					if (volume != null) {
						volume.setLevel(10 * volumeField.getValue());
					} else {
						details.setText("Volume control is not supported!!!");
					}
				}
			}
		});
	}
	
	public void initialize(Player player) {
		try {
			this.player = player;
			initialize();
		} catch (MediaException e) {
			throw new RuntimeException("ERROR:" + e);
		}
	}
	
	public void initialize(InputStream stream, String type) {
		try {
			player = Manager.createPlayer(stream, type);
			initialize();
		} catch (IOException e) {
			throw new RuntimeException("ERROR:" + e);
		} catch (MediaException e) {
			throw new RuntimeException("ERROR:" + e);
		}
	}

	public void initialize(String locator) {
		try {
			player = Manager.createPlayer(locator);
			initialize();
		} catch (IOException e) {
			throw new RuntimeException("ERROR:" + e);
		} catch (MediaException e) {
			throw new RuntimeException("ERROR:" + e);
		}
	}

	private void initialize() throws MediaException {
		player.addPlayerListener(new PlayerStateListener());
		player.prefetch();
		StringBuffer detailsText = new StringBuffer();
		detailsText.append("\nResource duration (seconds): ");
		detailsText.append(player.getDuration() / (1000 * 1000));
		detailsText.append("\nContent type: ");
		detailsText.append(player.getContentType());
		detailsText.append("\nControls: ");
		Control [] controls = player.getControls();
		for (int i = 0; i < controls.length; i++) {
			detailsText.append("\n    ");
			detailsText.append(getControlDetails(controls[i]));
		}
		details.setText(detailsText.toString());
	}

	private String getControlDetails(Control control) {
		String details;
		
		if (control instanceof FramePositioningControl) {
			details = "FramePositioningControl";
		} else if (control instanceof GUIControl) {
			details = "GUIControl";
		} else if (control instanceof MetaDataControl) {
			details = "MetaDataControl";
		} else if (control instanceof MIDIControl) {
			details = "MIDIControl";
		} else if (control instanceof PitchControl) {
			details = "PitchControl";
		} else if (control instanceof RateControl) {
			details = "RateControl";
		} else if (control instanceof RecordControl) {
			details = "RecordControl";
		} else if (control instanceof StopTimeControl) {
			details = "StopTimeControl";
		} else if (control instanceof TempoControl) {
			details = "TempoControl";
		} else if (control instanceof ToneControl) {
			details = "ToneControl";
		} else if (control instanceof VideoControl) {
			details = "VideoControl";
		} else if (control instanceof VolumeControl) {
			details = "VolumeControl";
		} else {
			details = "Unknown control type:" + control.getClass().getName();
		}
		
		return details;
	}
	
}
